package com.ld.common.util.task;

import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ScheduledFuture;

import org.apache.commons.collections.CollectionUtils;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;

import com.ld.admin.model.timedtask.SysTimedtaskLogModel;
import com.ld.admin.model.timedtask.SysTimedtaskModel;
import com.ld.admin.model.timedtask.SysTimedtaskUserInfo;
import com.ld.shieldsb.common.core.collections.ListUtils;
import com.ld.shieldsb.common.core.model.PropertiesModel;
import com.ld.shieldsb.common.core.model.Result;
import com.ld.shieldsb.common.core.reflect.ClassUtil;
import com.ld.shieldsb.common.core.util.StringUtils;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class TaskManager {
    private static final Map<String, SysTimedtaskModel> CACHE_MAP = new LinkedHashMap<>(); // 缓存
    private static final Map<String, ScheduledFuture<?>> SCHEDULEDFUTURE_MAP = new LinkedHashMap<>(); // 定时器缓存
    private static final ThreadPoolTaskScheduler THREAD_POOL_TASK_SCHEDULER = new ThreadPoolTaskScheduler();
    private static final Map<String, Set<String>> TASK_CLS_MAP = new HashMap<>(); // key为包名，value为包名下符合条件的类的名
    private static final Map<String, String> PKG_FILTER_MAP = new HashMap<>(); // 包名过滤设置，key为包名，value为此包名筛选的包名如ld.com（key）下值过滤包名中含有task（value）的目录
    static {
        THREAD_POOL_TASK_SCHEDULER.initialize(); // 线程池，调用前必须初始化
        getPkgNamesSet();
    }

    /**
     * 更新任务
     * 
     * @Title updateTask
     * @author 吕凯
     * @date 2020年7月1日 上午8:19:32
     * @param keyCode
     * @param taskModel
     *            void
     */
    public static Result updateTask(String keyCode, SysTimedtaskModel taskModel) {
        Result result = new Result();
        result.setSuccess(false);
        if (!CACHE_MAP.containsKey(keyCode)) {
            result.setMessage("识别码(Jobid)为" + keyCode + "的任务尚未注册请先注册！");
            return result;
        }
        CACHE_MAP.put(keyCode, taskModel);
        result.setSuccess(true);
        result.setData(taskModel);
        return result;
    }

    /**
     * 注册
     * 
     * @Title register
     * @author 吕凯
     * @date 2020年7月1日 上午8:19:42
     * @param taskModel
     * @return Result
     */
    public static Result register(SysTimedtaskModel taskModel, SysTimedtaskUserInfo userInfo) {
        Result result = new Result();
        result.setSuccess(false);
        String keyCode = taskModel.getJobId();
        if (StringUtils.isBlank(taskModel.getJobName())) {
            result.setMessage("name不能为空！");
            return result;
        }
        if (StringUtils.isBlank(keyCode)) {
            result.setMessage("识别码(KeyCode)不能为空！");
            return result;
        }
        SysTimedtaskModel cacheModel = CACHE_MAP.get(keyCode);
        if (cacheModel != null) {
            result.setMessage("识别码(Jobid)为" + keyCode + "的任务已经存在！监听器名称为：" + cacheModel.getJobName());
            return result;
        }
        // 文件监控线程
        log.warn("注册任务：" + taskModel.getJobName() + " Jobid:" + keyCode);
        // 添加监听
        CACHE_MAP.put(keyCode, taskModel);
        result.setSuccess(true);
        result.setData(taskModel);
        // 日志
        TimedTaskLogUtil.saveLogbyDB(SysTimedtaskLogModel.Type.TYPE_REGISTER, taskModel.getId(), "注册", userInfo);
        return result;
    }

    public static Result start(String keyCode, SysTimedtaskUserInfo userInfo) throws Exception {
        Result result = new Result();
        result.setSuccess(false);
        if (!CACHE_MAP.containsKey(keyCode)) {
            result.setMessage("识别码(Jobid)为" + keyCode + "的任务尚未注册，请先注册！");
            return result;
        }
        SysTimedtaskModel model = CACHE_MAP.get(keyCode);
        result = TaskManager.getInstance(model.getClassName());
        if (result.getSuccess()) {
            Object object = result.getData();
            if (object instanceof TaskThread) {
                TaskThread thread = (TaskThread) object;
                thread.setDaemon(true); // 设为守护线程
                thread.setKeyCode(keyCode); // keyCode设置
                thread.setTaskModel(model);
                thread.setData(model.getDatas());
                ScheduledFuture<?> future = THREAD_POOL_TASK_SCHEDULER.schedule(thread, new CronTrigger(model.getCronExpression()));
                SCHEDULEDFUTURE_MAP.put(keyCode, future);
                result.setSuccess(true);
            } else { // 不支持其他类
                SCHEDULEDFUTURE_MAP.remove(keyCode); // 移除
                result.setMessage("识别码(Jobid)为" + keyCode + "的任务启动失败，类型错误，应为Runnable或Thread！");
            }
        } else {
            SCHEDULEDFUTURE_MAP.remove(keyCode); // 移除
        }
        String message = "启动定时任务" + (result.getSuccess() ? "成功" : "失败") + "！";
        log.warn(message + model.getJobName() + "  Jobid:" + keyCode + "（id:" + model.getId() + "）");
        // 日志
        TimedTaskLogUtil.saveLogbyDB(SysTimedtaskLogModel.Type.TYPE_START, model.getId(), message, userInfo);
        return result;
    }

    /**
     * 停止任务
     * 
     * @Title stop
     * @author 吕凯
     * @date 2019年1月18日 上午9:03:57
     * @param keyCode
     * @return Result
     * @throws Exception
     */
    public static Result stop(String keyCode, SysTimedtaskUserInfo userInfo) throws Exception {
        Result result = new Result();
        result.setSuccess(false);
        if (!CACHE_MAP.containsKey(keyCode)) {
            result.setMessage("识别码(Jobid)为" + keyCode + "的任务尚未注册，请先注册！");
            return result;
        }
        SysTimedtaskModel model = CACHE_MAP.get(keyCode);
        ScheduledFuture<?> future = SCHEDULEDFUTURE_MAP.get(keyCode);
        if (future == null) {
            result.setMessage("识别码(Jobid)为" + keyCode + "的任务尚未启动！");
            return result;
        }
        future.cancel(true);
        SCHEDULEDFUTURE_MAP.remove(keyCode);
        result.setSuccess(true);
        log.warn("停止任务成功！" + keyCode + "（id:" + model.getId() + "）");
        // 日志
        TimedTaskLogUtil.saveLogbyDB(SysTimedtaskLogModel.Type.TYPE_STOP, model.getId(), "停止任务成功", userInfo);
        return result;
    }

    /**
     * 获取任务是否已完成
     * 
     * @Title isDone
     * @author 吕凯
     * @date 2019年3月22日 下午2:01:55
     * @param keyCode
     * @return
     * @throws Exception
     *             Boolean
     */
    @SuppressWarnings("null")
    public static Boolean isDone(String keyCode) throws Exception {
        ScheduledFuture<?> future = SCHEDULEDFUTURE_MAP.get(keyCode);
        if (future == null) {
            return future.isDone();
        }
        return false;
    }

    /**
     * 获取任务是否被取消
     * 
     * @Title isCancelled
     * @author 吕凯
     * @date 2019年3月22日 下午2:01:32
     * @param keyCode
     * @return
     * @throws Exception
     *             Boolean
     */
    @SuppressWarnings("null")
    public static Boolean isCancelled(String keyCode) throws Exception {
        ScheduledFuture<?> future = SCHEDULEDFUTURE_MAP.get(keyCode);
        if (future == null) {
            return future.isCancelled();
        }
        return false;
    }

    /**
     * 关闭任务管理器
     * 
     * @throws IOException
     */
    public static void shutdown() {
        Set<String> keySet = SCHEDULEDFUTURE_MAP.keySet();
        if (CollectionUtils.isNotEmpty(keySet)) {
            keySet.forEach(keyCode -> {
                try {
                    ScheduledFuture<?> future = SCHEDULEDFUTURE_MAP.get(keyCode);
                    future.cancel(true);
                } catch (Exception e) {
                    log.error("", e);
                }
            });
        }
        THREAD_POOL_TASK_SCHEDULER.destroy(); // 销毁线程池
        SCHEDULEDFUTURE_MAP.clear();
        CACHE_MAP.clear();
    }

    /**
     * 获取任务
     * 
     * @Title get
     * @author 吕凯
     * @date 2019年1月18日 下午3:28:39
     * @param keyCode
     * @return FileChangedListenerModel
     */
    public static SysTimedtaskModel get(String keyCode) {
        SysTimedtaskModel model = CACHE_MAP.get(keyCode);
        return model;
    }

    /**
     * 获取所有注册的任务
     * 
     * @Title getAllCacheModels
     * @author 吕凯
     * @date 2019年1月18日 下午3:28:56
     * @return Map<String,FileChangedListenerModel>
     */
    public static Map<String, SysTimedtaskModel> getAllCacheModels() {
        return CACHE_MAP;
    }

    /**
     * 获取类实例
     * 
     * @Title getInstance
     * @author 吕凯
     * @date 2019年3月4日 下午5:39:57
     * @param className
     * @return Result
     */
    public static Result getInstance(String className) {
        Result result = new Result();
        if (StringUtils.isBlank(className)) {
            result.setMessage("类名不能为空！");
        } else {
            Class<?> classType = ClassUtil.getClass(className);
            Object object = null;
            if (classType != null) {
                try {
                    if (TaskThread.class.isAssignableFrom(classType)) {

                        object = classType.newInstance(); // 改为直接使用反射
                        result.setSuccess(true);
                        result.setData(object);
                    } else {
                        result.setMessage("执行类只能为TaskThread的子类");
                        return result;
                    }
                } catch (Exception e) {
                    result.setMessage("实例化类出错：" + e.getMessage());
                    log.error("", e);
                }
            } else {
                result.setMessage("类未找到！");
            }
        }
        return result;
    }

    public static Result loadTaskClass() {
        return loadTaskClass(getPkgNamesSet());
    }

    /**
     * 加载task类
     * 
     * @Title loadTaskClass
     * @author 吕凯
     * @date 2019年3月5日 上午10:55:16
     * @param packageName
     * @param replace
     *            是否替换原来的类
     * @return Result
     */
    public static Result loadTaskClass(String packageName) {
        Result result = new Result();
        if (StringUtils.isBlank(packageName)) {
            result.setMessage("包名不能为空！");
        } else {
            Set<String> tasksRunnable = new HashSet<>();
            List<Class<? extends TaskThread>> runnableClassList = ClassUtil.getClassList(packageName, PKG_FILTER_MAP.get(packageName),
                    TaskThread.class, true); // 获取Runnable的子类
            for (Class<? extends Runnable> taskCls : runnableClassList) {
                log.warn("捕捉到一只可驯养为“定时任务”的类： " + taskCls.getName());
                tasksRunnable.add(taskCls.getName());
            }
            if (ListUtils.isNotEmpty(tasksRunnable)) {
                TASK_CLS_MAP.put(packageName, tasksRunnable);
            }
            result.setSuccess(true);
        }
        return result;
    }

    /**
     * 批量加载task类
     * 
     * @Title loadTaskClass
     * @author 吕凯
     * @date 2019年3月5日 下午4:52:34
     * @param packageNames
     * @return Result
     */
    public static Result loadTaskClass(List<String> packageNames) {
        Result result = new Result();
        if (ListUtils.isEmpty(packageNames)) {
            result.setMessage("包名不能为空！");
        } else {
            for (String pkgName : packageNames) {
                loadTaskClass(pkgName);
            }
            result.setSuccess(true);
        }
        return result;
    }

    /**
     * 获取所有的任务类
     * 
     * @Title getTaskClasses
     * @author 吕凯
     * @date 2019年3月5日 上午11:13:43
     * @return Set<String>
     */
    public static Set<String> getTaskClses() {
        Set<String> allTaskClses = new HashSet<>();
        Set<String> keys = TASK_CLS_MAP.keySet();
        if (ListUtils.isNotEmpty(keys)) {
            for (String key : keys) {
                allTaskClses.addAll(TASK_CLS_MAP.get(key));
            }
        }
        return allTaskClses;
    }

    /**
     * 获取命名空间（一般为包名）下的插件
     * 
     * @Title getPlugins
     * @author 吕凯
     * @date 2019年2月25日 上午10:38:40
     * @param nameSpace
     * @return List<Plugin>
     */
    public static Set<String> getTaskClses(String nameSpace) {
        return TASK_CLS_MAP.get(nameSpace);
    }

    /**
     * 获取配置的包名
     * 
     * @Title getPkgNamesSet
     * @author 吕凯
     * @date 2019年3月5日 下午4:47:47
     * @return List<String>
     */
    public static List<String> getPkgNamesSet() {
        List<String> pkgs = PropertiesModel.PROJECT.getStringList("application.taskcls.scanpkg");
        List<String> pkgFilters = PropertiesModel.PROJECT.getStringList("application.taskcls.scanpkg.pkgfilter");
        PKG_FILTER_MAP.clear();
        if (ListUtils.isNotEmpty(pkgs)) {
            for (int i = 0; i < pkgs.size(); i++) {
                String pkgName = pkgs.get(i);
                String pkgFilter = null;
                if (ListUtils.isNotEmpty(pkgFilters) && pkgFilters.size() > i) {
                    pkgFilter = pkgFilters.get(i);
                }
                PKG_FILTER_MAP.put(pkgName, pkgFilter);
            }
        }
        return pkgs;
    }

    /**
     * 获取包及包过滤设置的Map
     * 
     * @Title getPkgFilterMap
     * @author 吕凯
     * @date 2019年3月5日 下午5:10:28
     * @return Map<String,String>
     */
    public static Map<String, String> getPkgFilterMap() {
        return PKG_FILTER_MAP;
    }

    /**
     * 设置task类的扫描包及包过滤
     * 
     * @Title setPkgNamesSet
     * @author 吕凯
     * @date 2019年3月6日 下午2:51:01
     * @param scanpkg
     * @param pkgfilter
     * @return boolean
     */
    public static boolean setPkgNamesSet(String scanpkg, String pkgfilter) {
        PropertiesModel.PROJECT.save("application.taskcls.scanpkg", scanpkg);
        PropertiesModel.PROJECT.save("application.taskcls.scanpkg.pkgfilter", pkgfilter);
        return true;
    }

}
